//Nathan Popham
//4003-573-01: Procedural Shading
//Lab 4: Task 2 & 3 
//
//mybrick
// Textures a surface with a pattern of 1x1, 1x2, and 2x2 blocks. A predefined
// 5x5 pattern of these blocks is repeated across the surface.
//
// tilewidth    -   width of each tile (1x1 block is one tile)
// tileheight   -   height of each tile 
// mortarwidth  -   thickness of the mortar between blocks
// mortarcolor  -   color of the mortar between blocks
// brickcolor   -   color of the bricks
// octaves      -   octaves for color noise (set -1.0 for no noise)
// lacunity     -   lacunity of noise function
// gain         -   gain of noise function

#define snoise(x) (2*noise(x)-1)

//function described in Advanced Renderman by Apodaca & Gritz
// p. 253
float turbulence(point p; uniform float octaves, lacunarity, gain)
{
    varying float sum = 0, amp = 1;
    varying point pp = p;
    uniform float i;

    for(i = 0; i < octaves; i += 1)
    {
        sum += amp * abs(snoise(pp));
        amp *= gain; pp *= lacunarity;
    }
    return sum;
}

surface
mybrick ( float tilewidth = 2.0;
          float tileheight = 2.0;
          float mortarwidth = 0.2;
          color mortarcolor = color (0.0, 0.0, 0.0);
          color brickcolor1 = color(0.3, 0.3, 0.5);            
          color brickcolor2 = color(0.3, 0.5, 0.3);            
          color brickcolor3 = color(0.5, 0.3, 0.3);            
          float octaves = 6.0;
          float lacunity = 2.0;
          float gain = 0.8; 
        ) 
{
    normal Nf = faceforward(normalize(N), I);

    float numTilesWidth = 5.0;
    float numTilesHeight = 5.0;

    float TwoDIndex(float x, y, width) { return (x + y * width); }

    //unfortunately have to hardcode the array size
    //a 3.0 represents a tile with top and left mortar border
    //a 2.0 is a tile with only top mortar border
    //a 1.0 is a tile with only left mortar border
    //a 0.0 is a tile with no mortar borders
    float template[25.0] = 
        { 
            3.0, 2.0, 3.0, 3.0, 2.0,
            3.0, 3.0, 1.0, 3.0, 2.0,
            1.0, 3.0, 2.0, 3.0, 3.0,
            3.0, 2.0, 3.0, 1.0, 3.0,
            1.0, 0.0, 3.0, 2.0, 1.0
        };
     
    float brickColors[25.0] = 
        { 
            1.0, 1.0, 2.0, 3.0, 3.0,
            2.0, 3.0, 2.0, 1.0, 1.0,
            2.0, 1.0, 1.0, 3.0, 2.0,
            1.0, 1.0, 2.0, 3.0, 2.0,
            1.0, 1.0, 3.0, 3.0, 2.0
        };
    
    float is = (1.0 - s);
    float it = t;

    float brickColumn = floor(is*numTilesWidth - .0001);
    float brickRow = floor(it*numTilesHeight - .0001);
    float brickx = mod(is*numTilesWidth*tilewidth, tilewidth);
    float bricky = mod(it*numTilesHeight*tileheight, tileheight);
    
    float borderInfo = template[TwoDIndex(brickColumn, brickRow, numTilesWidth)];
    //float borderInfo = 0.0; 
    
    color brickcolor;
    float brickColorId = brickColors[TwoDIndex(brickColumn, brickRow, numTilesWidth)];
    if(brickColorId == 1.0)
        brickcolor = brickcolor1;
    else if(brickColorId == 2.0)
        brickcolor = brickcolor2;
    else
        brickcolor = brickcolor3;
    
    float colorNoise = 1.0;
    
    if(octaves > 0.0)
        colorNoise = turbulence(P, octaves, lacunity, gain);
    
    Ci = (ambient() + diffuse(Nf)) *
         mix(mortarcolor, brickcolor * colorNoise, (borderInfo == 2.0 || borderInfo == 0.0 || brickx > mortarwidth) && (borderInfo == 1.0 || borderInfo == 0.0 || bricky > mortarwidth)) * Os;
    Oi = Os;
}


